// Libc wrapper -- Wraps C functions to kernel functions.

#include <errno.h>
#include <Process.h>
#include <resource.h>
#include <FileDescriptor.h>
#include <ResourceManager.h>
#include <ProcessManager.h>
#include <SharedObject.h>
#include <string.h>
#include <sys/stat.h>

s32int syscall(u32int id)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id));
  return ret;
}
s32int syscall1(u32int id, s32int val)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val));
  return ret;
}
s32int syscall3(u32int id, s32int val1, s32int val2, s32int val3)
{
  s32int ret;
  asm volatile("int $30" : "=a"(ret) : "0" (id), "b" (val1), "c"(val2), "d"(val3));
  return ret;
}

#undef errno
extern int errno;

extern u32int _process;

extern "C" int close(int file)
{
  callResource(_process, Process_IF::destroyFileDescriptor, file);
  return 0;
}

extern "C" int execve(char *name, char **argv, char **env)
{
  callResource(_process, Process_IF::execve, name, argv, env);
  return -1;
}

extern "C" void _exit(int val)
{
  callResource(_process, Process_IF::exit, val);
}

extern "C" int fork()
{
  int ret = syscall(SYSCALL_FORK);
  u32int processManager = requestResource("ProcessManager");
  _process = callResource(processManager, ProcessManager_IF::getProcess, -1);
  return ret;
}

extern "C" int fstat(int file, struct stat * st)
{
  st->st_mode = S_IFCHR;
  return 0;
}

extern "C" int getpid()
{
  return callResource(_process, Process_IF::getPid);
}

extern "C" int isatty(int file)
{
  return 1;
}

extern "C" int _isatty(int file)
{
  return 1;
}

extern "C" int kill(int pid, int sig)
{
  errno = EBUSY;
  return -1;
}

extern "C" int link(char *old, char *_new)
{
  errno = EBUSY;
  return -1;
}

extern "C" int lseek(int file, int ptr, int dir)
{
  if (file < 0) {return -1;}
  u32int fd = callResource(_process, Process_IF::getFileDescriptor, file);
  return callResource(fd, FileDescriptor_IF::seek, ptr, dir);
}

extern "C" int open(const char *name, int flags, int mode)
{
  u32int resourceManager = requestResource("ResourceManager");
  char *new_name = (char*)callResource(resourceManager, ResourceManager_IF::share, name, strlen(name)+1);
  u32int fd = callResource(_process, Process_IF::createFileDescriptor, new_name, mode, flags);
  callResource(resourceManager, ResourceManager_IF::unshare, new_name, NULL, 0);
  if (!fd)
  {
    errno = ENOENT;
    return -1;
  }
  else
  {
    return callResource(fd, FileDescriptor_IF::getId);
  }
}

extern "C" int read(int file, char *ptr, int len)
{
  if (file < 0) {return -1;}
  
  u32int resourceManager = requestResource("ResourceManager");
  u32int bufResource = (u32int)callResource(resourceManager, ResourceManager_IF::mkbuf, len);
  
  u32int fd = callResource(_process, Process_IF::getFileDescriptor, file);
  int ret = callResource(fd, FileDescriptor_IF::read, len, bufResource);
  
  Address bufAddr = (Address)callResource(bufResource, SharedObject_IF::permit, getpid(), true);
  memcpy((u8int*)ptr, (const u8int*)bufAddr, len);
  
  callResource(resourceManager, ResourceManager_IF::freebuf, bufResource);

  return ret;
}

extern "C" int sbrk(int incr)
{
  return callResource(_process, Process_IF::sbrk, incr);
}

extern "C" int stat(const char *file, struct stat * st)
{
  errno = EBUSY;
  return -1;
}

extern "C" int times(void *buf)
{
  errno = EBUSY;
  return -1;
}

extern "C" int unlink(char *name)
{
  errno = EBUSY;
  return -1;
}

//extern "C" int wait(int *status)
//{
//  errno = EBUSY;
//  return -1;
//}

extern "C" int write(int file, char *ptr, int len)
{
  if (file < 0) {return -1;}
  
  u32int resourceManager = requestResource("ResourceManager");
  u32int bufResource = (u32int)callResource(resourceManager, ResourceManager_IF::mkbuf, len);
  Address bufAddr = (Address)callResource(bufResource, SharedObject_IF::permit, getpid(), true);
  memcpy((u8int*)bufAddr, (const u8int*)ptr, len);
  
  u32int fd = callResource(_process, Process_IF::getFileDescriptor, file);
  int ret = callResource(fd, FileDescriptor_IF::write, len, bufResource);
  callResource(resourceManager, ResourceManager_IF::freebuf, bufResource);
  
  return ret;
}

extern "C" int lstat(char *file, struct stat *st)
{
  errno = EBUSY;
  return -1;
}
